import { app, BrowserWindow, ipcMain, webContents, Tray, shell } from 'electron'
import { electronApp, optimizer, is } from '@electron-toolkit/utils'
import appIcon from '../../build/icon.png?asset'
const http = require('http')
const fs = require('fs')
const WebSocket = require('ws')
const path = require('path')
const Store = require('electron-store')
const ffi = require('ffi-napi')
const ref = require('ref-napi')
const xml2js = require('xml2js')
const axios = require('axios')
const parser = new xml2js.Parser({ explicitArray: false })
const isSecondInstance = app.requestSingleInstanceLock()
const appPath = app.getAppPath()
const fileStr = is.dev ? 'resources' : '..'
let wsClient,
  userInfo,
  loginWindow,
  mainWindow,
  tray,
  processId,
  downloadPromise,
  optionGroupSettingRes
let shouldCreat = false
let followSettingRes = {
  personal: [], //跟个人源头消息
  official: [] //跟官方源头消息
}
const store = new Store()
const WxLoaderFile = path.join(appPath, fileStr, 'NoveLoader_x64.dll')
const WeChatHelperFile = path.join(appPath, fileStr, 'NoveHelper_3.9.10.19.dll')
const WeChatHelperVersion = '3.9.10.19'
const queue = []
if (!isSecondInstance) {
  app.quit()
} else {
  app.on('second-instance', (event, commandLine, workingDirectory) => {
    // 当尝试启动第二个实例时，将焦点转移到已经运行的实例
    if (loginWindow) {
      if (loginWindow.isMinimized()) loginWindow.restore()
      loginWindow.focus()
    }
    if (mainWindow) {
      if (mainWindow.isMinimized()) mainWindow.restore()
      mainWindow.focus()
    }
  })
}
// 获取当前时间
const getT = (n = 0) => {
  const targetDate = new Date()
  targetDate.setDate(targetDate.getDate() - n)
  const year = targetDate.getFullYear()
  const month = String(targetDate.getMonth() + 1).padStart(2, '0')
  const day = String(targetDate.getDate()).padStart(2, '0')
  const hour = String(targetDate.getHours()).padStart(2, '0')
  const minute = String(targetDate.getMinutes()).padStart(2, '0')
  const second = String(targetDate.getSeconds()).padStart(2, '0')
  const millisecond = String(targetDate.getMilliseconds()).padStart(3, '0')
  const formattedDate = `${year}${month}${day},${hour}:${minute}:${second}.${millisecond}`
  return formattedDate
}
// 封装函数：确保文件夹路径存在
const ensureDirectoryExists = (directoryPath) => {
  if (!fs.existsSync(directoryPath)) {
    fs.mkdirSync(directoryPath, { recursive: true })
  }
}
// 封装函数：确保文件路径存在
const ensureFileExists = (filePath) => {
  if (!fs.existsSync(filePath)) {
    fs.writeFileSync(filePath, '', 'utf8')
  }
}
// 判断值是否为数字，并转换为字符串
const convertToString = (value) => {
  return String(value)
}
// 写日志
const creatLog = (logData, str = '') => {
  let filePathLog = null
  const dateFormat = getT().split(',')
  if (!userInfo) {
    filePathLog = path.join(process.cwd(), 'setting', 'applog.json')
  } else {
    const filePath = path.join(process.cwd(), 'setting', userInfo.inviteCode)
    const datePath = path.join(filePath, 'log', dateFormat[0])
    filePathLog = path.join(datePath, 'o.json')
    ensureDirectoryExists(filePath)
    ensureDirectoryExists(datePath)
  }
  ensureFileExists(filePathLog)
  fs.readFile(filePathLog, 'utf8', async (error, data) => {
    // 解析JSON数据
    let logJson = data ? JSON.parse(data) : {}
    let res = {
      data: logData,
      desc: str
    }
    logJson[dateFormat[1]] = res
    // 将修改后的数据转换为JSON格式
    const updatedData = JSON.stringify(logJson, null, 2)
    // 将更新后的数据写回文件
    fs.writeFile(filePathLog, updatedData, 'utf8', () => {})
  })
}
// 通过cdnurl下载gif
const downloadGif = (cdnUrl) => {
  return new Promise((resolve, reject) => {
    http.get(cdnUrl, (response) => {
      let fileData = Buffer.alloc(0)
      response.on('data', (chunk) => {
        fileData = Buffer.concat([fileData, chunk])
      })
      response.on('end', () => {
        resolve(fileData)
      })
      response.on('error', (error) => {
        creatLog(error, 'downloadGif-response')
        resolve(false)
      })
    })
  })
}
// 保存网络路径到本地
const saveUrl = (url, mWxid, uWxid, fName, uName, uExt) => {
  return new Promise((resolve, reject) => {
    const date = getT().split(',')[0]
    const filePath = path.join(
      process.cwd(),
      'localcache',
      convertToString(date),
      convertToString(mWxid),
      convertToString(fName),
      convertToString(uWxid)
    )
    ensureDirectoryExists(filePath)
    const fileName = `${uName}.${uExt}`
    // 构建本地保存的文件路径
    const fileFullPath = path.join(filePath, fileName)
    if (fs.existsSync(fileFullPath)) {
      resolve(fileFullPath)
    } else {
      // 发送 GET 请求获取图片数据
      axios({
        method: 'get',
        url: url,
        responseType: 'stream'
      })
        .then(function (response) {
          // 创建可写流
          const fileStream = fs.createWriteStream(fileFullPath)
          // 将网络响应管道到本地文件
          response.data.pipe(fileStream)
          // 监听完成事件
          fileStream.on('finish', () => {
            resolve(fileFullPath)
          })
          fileStream.on('error', (error) => {
            creatLog(error, 'fileStream-error')
            resolve()
          })
        })
        .catch(function (error) {
          creatLog(error, 'axios-stream-catch')
          resolve()
        })
    }
  })
}

// 保存文件
const saveFile = (mWxid, uWxid, fName, uName, uExt, fData) => {
  const date = getT().split(',')[0]
  const filePath = path.join(process.cwd(), 'localcache', date, mWxid, fName, uWxid)
  ensureDirectoryExists(filePath)
  const fileName = `${uName}.${uExt}`
  const fileFullPath = path.join(filePath, fileName)
  if (fs.existsSync(fileFullPath)) {
    return fileFullPath
  } else {
    try {
      // 写入文件
      fs.writeFileSync(fileFullPath, Buffer.from(fData))
      return fileFullPath
    } catch (error) {
      creatLog(error, 'saveFile-catch-error')
      return null
    }
  }
}
// 统计
const creatStatic = (staticNum = null) => {
  if (!userInfo) return
  const filePath = path.join(process.cwd(), 'setting', userInfo.inviteCode)
  const dateFormat = getT().split(',')
  const datePath = path.join(filePath, 'log', dateFormat[0])
  let filePathStatic = path.join(datePath, 's.json')
  ensureDirectoryExists(filePath)
  ensureDirectoryExists(datePath)
  ensureFileExists(filePathStatic)
  fs.readFile(filePathStatic, 'utf8', async (error, data) => {
    if (error) {
      creatLog(error, 'readFile-filePathStatic')
    }
    try {
      // 解析JSON数据
      let staticJson = data ? JSON.parse(data) : {}
      if (staticNum) {
        for (let key in staticNum) {
          if (!staticJson[key]) staticJson[key] = 0
          staticJson[key] = staticJson[key] + staticNum[key]
        }
      }
      mainWindow?.webContents.send('sendNum', staticJson)
      // 将修改后的数据转换为JSON格式
      const updatedData = JSON.stringify(staticJson, null, 2)
      // 将更新后的数据写回文件
      fs.writeFile(filePathStatic, updatedData, 'utf8', (error) => {
        if (error) {
          creatLog(error, 'writeFile-filePathStatic-error')
        }
      })
    } catch (error) {
      creatLog(error, 'filePathStatic-try-catch')
    }
  })
}

class CustomWebSocket {
  constructor(url) {
    this.url = url
    this.connect()
  }
  connect() {
    this.ws = new WebSocket(this.url)
    this.ws.on('open', () => {
      console.log('WebSocket connected')
    })
    this.ws.on('message', (data) => {
      this.handleMessage(data)
    })
    this.ws.on('close', () => {
      this.reconnect()
    })
    this.ws.on('error', (error) => {
      creatLog(error, 'CustomWebSocket-on-error')
    })
  }
  reconnect() {
    setTimeout(() => {
      this.connect()
    }, 5000)
  }
  send(data) {
    if (this.ws.readyState === this.ws.OPEN) {
      const sendMessage = JSON.stringify(data)
      this.ws.send(sendMessage)
    }
  }
  close() {
    if (this.ws) {
      this.ws.close()
    }
  }
}

// 跟发关系二次处理
const setfollowSettingRes = (res) => {
  const result = {
    personal: [],
    official: []
  }
  if (!res || JSON.stringify(res) === '{}') return result
  for (const key in res) {
    if (!res[key].isOpen) continue //剔除跟发按钮处于关闭状态的
    if (res[key].type == 1) {
      // 跟官方的
      result.official.push({
        wxid1: res[key].Id, //源头群系统id
        recvWxid: res[key].wxid, //源头群
        wxid3: key //转发群
      })
    } else {
      // 跟个人群的
      res[key].Member.forEach((item) => {
        result.personal.push({
          wxid1: res[key].wxid, //源头群
          wxid2: item.wxid, //主持人
          wxid3: key //转发群
        })
      })
    }
  }
  return result
}

// 递归地删除文件夹及其内容
const deleteFolderRecursive = (folderPath) => {
  if (fs.existsSync(folderPath)) {
    fs.readdirSync(folderPath).forEach((file, index) => {
      const curPath = path.join(folderPath, file)
      if (fs.lstatSync(curPath).isDirectory()) {
        // 递归删除文件夹
        deleteFolderRecursive(curPath)
      } else {
        // 删除文件
        fs.unlinkSync(curPath)
        console.log(`文件 ${curPath} 已成功删除。`)
      }
    })
    fs.rmdirSync(folderPath) // 删除空文件夹
  }
}

// 删除缓存的图片和表情文件
const deleteOldCacheFolders = () => {
  const folderPath = path.join(process.cwd(), 'localcache')
  const todayFolder = getT().split(',')[0]
  const yesterdayFolder = getT(1).split(',')[0]
  fs.readdirSync(folderPath).forEach((fileItem) => {
    if (fileItem !== todayFolder && fileItem !== yesterdayFolder) {
      const folderPath = path.join('localcache', fileItem)
      deleteFolderRecursive(folderPath)
    }
  })
}

// 删除设置中7天前的日志
const deleteOldLogFolders = () => {
  const today = new Date()
  const daysAgo = new Date(today.setDate(today.getDate() - 7))
  const year = String(daysAgo.getFullYear()).padStart(4, '0')
  const month = String(daysAgo.getMonth() + 1).padStart(2, '0')
  const day = String(daysAgo.getDate()).padStart(2, '0')
  const formattedDate = `${year}${month}${day}`
  const folderPath = path.join(process.cwd(), 'setting', userInfo.inviteCode, 'log')
  setTimeout(() => {
    fs.readdirSync(folderPath).forEach((fileDate) => {
      if (Number(fileDate) < Number(formattedDate)) {
        const filePath = path.join(folderPath, fileDate)
        fs.unlinkSync(filePath)
      }
    })
  }, 500)
}

//微信函数
function InitLoader(loader_path) {
  var loader = path.resolve(loader_path)
  var lib = ffi.DynamicLibrary(loader)
  var _handle = lib._handle

  var InitWeChatSocketPtr = _handle.reinterpret(ref.sizeof.pointer, 0xb3a0)
  var InitWeChatSocket = ffi.ForeignFunction(
    InitWeChatSocketPtr,
    'bool',
    ['pointer', 'pointer', 'pointer'],
    ffi.FFI_STDCALL
  )

  var InjectWeChatPtr = _handle.reinterpret(ref.sizeof.pointer, 0xcf70)
  var InjectWeChat = ffi.ForeignFunction(InjectWeChatPtr, 'uint', ['string'], ffi.FFI_STDCALL)

  var InjectWeChatPidPtr = _handle.reinterpret(ref.sizeof.pointer, 0xbb80)
  var InjectWeChatPid = ffi.ForeignFunction(
    InjectWeChatPidPtr,
    'uint',
    ['uint', 'string'],
    ffi.FFI_STDCALL
  )

  var InjectWeChatMultiOpenPtr = _handle.reinterpret(ref.sizeof.pointer, 0xcbb0)
  var InjectWeChatMultiOpen = ffi.ForeignFunction(
    InjectWeChatMultiOpenPtr,
    'uint',
    ['string', 'string'],
    ffi.FFI_STDCALL
  )

  var InjectWeChat2Ptr = _handle.reinterpret(ref.sizeof.pointer, 0xc660)
  var InjectWeChat2 = ffi.ForeignFunction(
    InjectWeChat2Ptr,
    'uint',
    ['string', 'string'],
    ffi.FFI_STDCALL
  )

  var _GetUserWeChatVersionPtr = _handle.reinterpret(ref.sizeof.pointer, 0xb310)
  var _GetUserWeChatVersion = ffi.ForeignFunction(
    _GetUserWeChatVersionPtr,
    'bool',
    ['pointer'],
    ffi.FFI_STDCALL
  )

  var SendWeChatDataPtr = _handle.reinterpret(ref.sizeof.pointer, 0xb2e0)
  var SendWeChatData = ffi.ForeignFunction(
    SendWeChatDataPtr,
    'bool',
    ['uint', 'string'],
    ffi.FFI_STDCALL
  )

  var DestroyWeChatPtr = _handle.reinterpret(ref.sizeof.pointer, 0xc900)
  var DestroyWeChat = ffi.ForeignFunction(DestroyWeChatPtr, 'bool', [], ffi.FFI_STDCALL)

  var UseUtf8Ptr = _handle.reinterpret(ref.sizeof.pointer, 0xcac0)
  var UseUtf8 = ffi.ForeignFunction(UseUtf8Ptr, 'bool', [], ffi.FFI_STDCALL)

  var UnjectWeChatPtr = _handle.reinterpret(ref.sizeof.pointer, 0xcaf0)
  var UnjectWeChat = ffi.ForeignFunction(UnjectWeChatPtr, 'bool', ['uint32'], ffi.FFI_STDCALL)

  var DestroyWeChatThreadPtr = _handle.reinterpret(ref.sizeof.pointer, 0xce50)
  var DestroyWeChatThread = ffi.ForeignFunction(
    DestroyWeChatThreadPtr,
    'bool',
    ['uint32'],
    ffi.FFI_STDCALL
  )

  // 设置使用 UTF8 编码
  UseUtf8()

  var InitCallback = function (onConnect, onReceive, onClose) {
    // 新客户端加入的回调
    var connect = ffi.Callback('void', ['int'], ffi.FFI_STDCALL, onConnect)
    // 客户端退出回调
    var close = ffi.Callback('void', ['int'], ffi.FFI_STDCALL, onClose)
    // 接收消息回调
    var receive = ffi.Callback(
      'void',
      ['int', 'string', 'int'],
      ffi.FFI_STDCALL,
      function (cid, raw, length) {
        var { type, data, trace } = JSON.parse(raw)
        onReceive(cid, trace ? { type, data, trace } : { type, data })
      }
    )
    // 使用闭包初始化接口
    return () => InitWeChatSocket(connect, receive, close)
  }

  var GetUserWeChatVersion = function () {
    var wxVersionBuffer = Buffer.alloc(20, '\0', 'binary')
    _GetUserWeChatVersion(wxVersionBuffer)
    return wxVersionBuffer.toString('binary').replace(/\0+$/, '')
  }

  return {
    InitCallback,
    GetUserWeChatVersion,
    InjectWeChat,
    InjectWeChatPid,
    InjectWeChatMultiOpen,
    InjectWeChat2,
    SendWeChatData,
    UnjectWeChat,
    DestroyWeChatThread
  }
}
function connectCallback(iClientId) {
  processId = iClientId
}

function closeCallback(iClientId) {
  processId = null
  mainWindow?.webContents.send('closeCallback')
}

function recvCallback(iClientId, { type, data }) {
  if (type == 11025) {
    // 微信登录成功！
    mainWindow?.webContents.send('loginWeiXinSuccess', data)
    // cdn初始化
    const res = WxLoader.SendWeChatData(
      processId,
      JSON.stringify({
        type: 11228,
        data: {}
      })
    )
  } else if (type == 11031) {
    // 获取到群组列表
    mainWindow?.webContents.send('recvWxGroupList', data)
  } else if (type == 11032) {
    // 获取群成员
    mainWindow?.webContents.send('recvWxGroupMember', data)
  } else if (type == 11228) {
    // 初始化
    creatLog(data, 'initcdn')
  } else if (type == 11230) {
    // 下载文件
    if (data.error_code == 0 && data.save_path) {
      WxLoader.SendWeChatData(
        processId,
        JSON.stringify({
          type: downloadPromise?.targetData.num2,
          data: {
            to_wxid: downloadPromise.reJson.wxid3,
            file: data.save_path
          }
        })
      )
      creatLog({
        desc: `发送${downloadPromise.reJson.official ? '官方' : ''}非文字消息`,
        msgid: downloadPromise.reJson.msgid,
        msg: downloadPromise.reJson.msg,
        wxid: downloadPromise.reJson.wxid3
      })
    }
    setTimeout(() => {
      run()
    }, downloadPromise?.targetData?.interval ?? 1000)
  } else if ([11046, 11047, 11051, 11052].includes(type)) {
    // 获取群消息
    if (!followSettingRes?.personal?.length) return
    if (!data.room_wxid || !data.room_wxid.includes('@chatroom')) return
    followSettingRes.personal.forEach((item) => {
      if (item.wxid1 == data.room_wxid && item.wxid2 == data.from_wxid) {
        queue.push({
          ...data,
          wxid1: item.wxid1,
          wxid2: item.wxid2,
          wxid3: item.wxid3,
          recvWxid: data.to_wxid,
          official: false
        })
      }
    })
  }
}
const WxLoader = InitLoader(WxLoaderFile)
function creatLoginWindow() {
  loginWindow = new BrowserWindow({
    width: 500,
    height: 400,
    resizable: false,
    icon: appIcon,
    show: false,
    frame: false,
    titleBarStyle: 'hidden',
    autoHideMenuBar: true,
    webPreferences: {
      preload: path.join(__dirname, '../preload/index.js'),
      sandbox: false,
      nodeIntegration: true,
      // 禁用同源策略，允许跨域请求
      webSecurity: false
    }
  })
  if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
    loginWindow.loadURL(process.env['ELECTRON_RENDERER_URL'])
  } else {
    loginWindow.loadFile(path.join(__dirname, '../renderer/index.html'))
  }
  // 打开开发者工具
  loginWindow.once('ready-to-show', () => {
    loginWindow.show() // 显示窗口
  })
  loginWindow.on('closed', () => {
    loginWindow = null // 窗口关闭时将变量置为 null
    if (shouldCreat) {
      shouldCreat = false
      creatMainWindow()
    }
  })
}

async function creatMainWindow() {
  mainWindow = new BrowserWindow({
    width: 1200,
    height: 800,
    minWidth: 1400,
    minHeight: 800,
    icon: appIcon,
    show: false,
    frame: false,
    titleBarStyle: 'hidden',
    autoHideMenuBar: true,
    webPreferences: {
      preload: path.join(__dirname, '../preload/index.js'),
      sandbox: false,
      nodeIntegration: true,
      // 禁用同源策略，允许跨域请求
      webSecurity: false
    }
  })
  if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
    mainWindow.webContents.openDevTools()
    mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL'])
  } else {
    mainWindow.loadFile(path.join(__dirname, '../renderer/index.html'))
  }
  // mainWindow.webContents.openDevTools()
  // 创建托盘图标
  tray = new Tray(appIcon)
  // 设置托盘图标的提示文本
  tray.setToolTip('发单小助手')
  // 点击托盘图标时显示或隐藏窗口
  tray.on('click', () => {
    mainWindow.isVisible() ? mainWindow.hide() : mainWindow.show()
  })
  // 转备好后打开窗口
  mainWindow.once('ready-to-show', () => {
    mainWindow.show() // 显示窗口
  })
  // // 在窗口关闭时隐藏窗口，并阻止默认关闭行为
  // mainWindow.on('close', (event) => {
  //   if (!app.isQuitting) {
  //     event.preventDefault()
  //     mainWindow.hide()
  //   }
  // })
  mainWindow.on('closed', () => {
    mainWindow = null // 窗口关闭时将变量置为 null
    if (shouldCreat) {
      shouldCreat = false
      creatLoginWindow()
    }
  })
  userInfo = await store.get('userInfo')
  wsClient?.send({ wsMsgType: 'configGet', openId: userInfo.openId })
  deleteOldLogFolders()
}
app.whenReady().then(() => {
  electronApp.setAppUserModelId('com.electron')
  app.on('browser-window-created', (_, window) => {
    optimizer.watchWindowShortcuts(window)
  })
  creatWsClient()
  creatLoginWindow()
  /*监听来自渲染层的事件*/
  // 监听登陆成功进入首页
  ipcMain.on('afterLogin', (event) => {
    shouldCreat = true
    if (loginWindow && !loginWindow.isDestroyed()) {
      // 进行操作前先检查窗口是否存在且未被销毁
      loginWindow.close()
    }
  })
  // 监听退出登录和切换账号
  ipcMain.on('afterOutLogin', async () => {
    shouldCreat = true
    WxLoader.DestroyWeChatThread(processId)
    const keys = Object.keys(store.store)
    for (const key of keys) {
      if (key != 'passwordForm') {
        await store.delete(key)
      }
    }
    if (mainWindow && !mainWindow.isDestroyed()) {
      // 进行操作前先检查窗口是否存在且未被销毁
      mainWindow.close()
    }
  })
  // 获取统计数据
  ipcMain.on('onCreatStatic', async () => {
    creatStatic()
  })
  // 监听退出登录微信
  ipcMain.on('outWx', async () => {
    WxLoader.DestroyWeChatThread(processId)
  })
  // 窗口最小化
  ipcMain.on('minimizeWindow', () => {
    mainWindow?.minimize()
  })
  // 窗口全屏
  ipcMain.on('toggleFullscreen', (event, fullscreen) => {
    mainWindow?.setFullScreen(fullscreen)
  })
  // 监听用户点击退出
  ipcMain.on('appClose', async () => {
    app.quit()
  })
  // 监听设置缓存操作
  ipcMain.handle('storeGet', (event, key) => {
    const data = store.get(key)
    return data
  })
  // 监听获取缓存操作
  ipcMain.handle('storeSet', (event, key, value) => {
    store.set(key, value)
  })
  // 监听删除缓存操作
  ipcMain.handle('storeDel', (event, key) => {
    store.delete(key)
  })
  // 监听渲染层点击启动微信
  ipcMain.on('initWxFun', () => {
    if (processId) return
    const wxVersion = WxLoader.GetUserWeChatVersion()
    if (!wxVersion) {
      // 未安装微信
      mainWindow?.webContents.send('versionMis', {
        current: false,
        target: WeChatHelperVersion
      })
    } else if (wxVersion != WeChatHelperVersion) {
      // 微信版本不对，提示安装
      mainWindow?.webContents.send('versionMis', {
        current: wxVersion,
        target: WeChatHelperVersion
      })
    } else {
      WxLoader.InitCallback(connectCallback, recvCallback, closeCallback)()
      WxLoader.InjectWeChat(WeChatHelperFile)
      mainWindow?.webContents.send('versionMis', {
        reday: true
      })
    }
  })
  ipcMain.on('sendToWebSocket', (event, message) => {
    wsClient?.send(message)
  })
  // 监听插消息事件
  ipcMain.on('insertMsgs', (event, data) => {
    queue = queue.concat(data)
  })
  // 获取微信群列表
  ipcMain.on('getWxGroupList', (event) => {
    WxLoader.SendWeChatData(
      processId,
      JSON.stringify({
        type: 11031,
        data: {
          detail: 0
        }
      })
    )
  })
  // 获取微信群成员列表
  ipcMain.on('getWxGroupMember', (event, wxidO) => {
    WxLoader.SendWeChatData(
      processId,
      JSON.stringify({
        type: 11032,
        data: {
          room_wxid: wxidO
        }
      })
    )
  })
  // 接收跟发关系改变通知或者群设置改变通知
  ipcMain.on('getSetting', (event, res) => {
    const filePath = path.join(process.cwd(), 'setting', userInfo.inviteCode)
    const resultFilePath = path.join(filePath, 'settings.json')
    const str = res.type
    if (str === 'followSetting') followSettingRes = setfollowSettingRes(res.result)
    else {
      wsClient?.send({
        wsMsgType: 'configSave',
        openId: userInfo.openId,
        groupConfig: JSON.stringify(res.data)
      })
    }
    fs.readFile(resultFilePath, 'utf8', (err, data) => {
      if (err) {
        creatLog(err, 'readFile-resultFilePath-err')
      }
      try {
        const jsonData = data ? JSON.parse(data) : {}
        jsonData['groupConfig'][str] = res.data
        const updatedData = JSON.stringify(jsonData, null, 2)
        fs.writeFile(resultFilePath, updatedData, 'utf8', (err) => {
          if (err) {
            creatLog(err, 'writeFile-resultFilePath-catch')
          }
        })
      } catch (error) {
        creatLog(error, 'resultFilePath-try-catch')
      }
    })
  })
  // 安装微信
  ipcMain.on('installWeixin', () => {
    shell.openExternal('https://msadmin.maishou88.com/static/WeChatSetup_3.9.10.19.exe')
    // shell.openExternal('https://msadmin.maishou88.com/static/cloudpc-setup.exe')
  })
  // 渲染层写日志
  ipcMain.on('creatLog', (event, res) => {
    creatLog(res)
  })
  // 读取日志
  ipcMain.handle('readLog', async () => {
    const filePath = path.join(process.cwd(), 'setting', userInfo.inviteCode)
    const date = getT().split(',')[0]
    const datePath = path.join(filePath, 'log')
    const filePathLog = path.join(datePath, `${date}.json`)
    return new Promise((resolve, reject) => {
      fs.readFile(filePathLog, 'utf8', (error, data) => {
        if (error) {
          creatLog(error, 'readFile-filePathLog-error')
          reject(error)
        }
        let jsonData = data ? JSON.parse(data) : {}
        resolve(jsonData)
      })
    })
  })
})

// 在这里添加自定义的异常处理逻辑
process.on('uncaughtException', (error) => {
  creatLog(error, 'uncaughtException')
})

app.on('activate', function () {
  // if (BrowserWindow.getAllWindows().length === 0) creatLoginWindow()
})

app.on('will-finish-launching', async () => {
  const keys = Object.keys(store.store)
  for (const key of keys) {
    if (key != 'passwordForm') {
      await store.delete(key)
    }
  }
  deleteOldCacheFolders()
})

app.on('before-quit', () => {
  // 在这里执行必要的清理工作
  if (wsClient) wsClient?.close
})

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

// 创建ws
const creatWsClient = () => {
  wsClient = new CustomWebSocket('ws://saas-pc-gateway.corpvip.top:7272')
  wsClient.handleMessage = async (data) => {
    let textData = data
    if (Buffer.isBuffer(textData)) {
      textData = textData.toString()
    }
    textData = JSON.parse(textData)
    if (textData?.type == 'ping') {
      // 心跳
      wsClient?.send('ping')
    } else if (textData.code == 101) {
      // 用户验证
      if (userInfo) {
        wsClient?.send({
          wsMsgType: 'reConnect',
          accessToken: userInfo.accessToken
        })
      }
    } else if (textData?.data?.wsMsgType == 'sourceChatData') {
      // 官方源头群消息
      if (!followSettingRes?.official?.length) return
      const officialMsg = textData?.data?.list ?? []
      if (!officialMsg.length) return
      followSettingRes.official.forEach((item) => {
        officialMsg.forEach((ele) => {
          if (item.wxid1 == ele.sourceChatRoomId) {
            queue.push({
              msg: ele.content,
              wx_type: ele.msgType,
              wxid1: item.wxid1,
              wxid3: item.wxid3,
              recvWxid: item.recvWxid,
              msgid: ele.id,
              official: true
            })
          }
        })
      })
    } else if (textData?.data?.wsMsgType == 'configGet') {
      let list = textData?.data?.list
      creatSetting(list)
    } else {
      webContents.getAllWebContents().forEach((wc) => {
        wc.send('webSocketMessage', textData)
      })
    }
  }
}

//创建设置文件
const creatSetting = (list) => {
  // 检测当前登录用户是在本地存储了日志和设置文件，有则读取，无则创建
  const filePath = path.join(process.cwd(), 'setting', userInfo.inviteCode)
  const filePathSetting = path.join(filePath, 'settings.json')
  ensureDirectoryExists(filePath)
  ensureFileExists(filePathSetting)
  fs.readFile(filePathSetting, 'utf8', async (error, data) => {
    if (error) {
      creatLog(error, 'readFile-filePathSetting')
    }
    try {
      // 解析JSON数据
      let settingJson = data ? JSON.parse(data) : {}
      if (!settingJson.groupConfig) settingJson.groupConfig = {}
      if (!settingJson.groupConfig.optionGroupSetting)
        settingJson.groupConfig.optionGroupSetting = {}
      if (!settingJson.groupConfig.followSetting) settingJson.groupConfig.followSetting = {}
      if (list && list.groupConfig) {
        settingJson.groupConfig.optionGroupSetting = JSON.parse(list.groupConfig)
      }
      let optionGroupSetting = settingJson.groupConfig.optionGroupSetting
      let followSetting = settingJson.groupConfig.followSetting
      if (JSON.stringify(followSetting) !== '{}') {
        for (const key in followSetting) {
          if (JSON.stringify(followSetting[key]) !== '{}') {
            for (const m in followSetting[key]) {
              followSetting[key][m]['isOpen'] = false
            }
          }
        }
      }
      settingJson.groupConfig.followSetting = followSetting
      store.set('followSetting', followSetting)
      if (JSON.stringify(optionGroupSetting) == '{}') {
        const configKeywordData = await axios.post(
          'http://saas-pc-gateway.corpvip.top:8789/getSourceChatroomConfigKeyword',
          { openId: userInfo?.openId }
        )
        const optionGroupSettingRe = {
          interval: 0.1,
          filterWord: configKeywordData?.data?.data?.list ?? [],
          replaceWord: [
            {
              keyword: '',
              words: ['']
            }
          ],
          customCopy: {
            position: 'start',
            text: ''
          },
          filterPic: false,
          filterEmoji: false
        }
        optionGroupSetting = optionGroupSettingRe
      }
      optionGroupSettingRes = optionGroupSetting
      settingJson.groupConfig.optionGroupSetting = optionGroupSettingRes
      store.set('optionGroupSetting', optionGroupSettingRes)
      // 将修改后的数据转换为JSON格式
      const updatedData = JSON.stringify(settingJson, null, 2)
      // 通知服务端更新设置
      wsClient?.send({
        wsMsgType: 'configSave',
        openId: userInfo.openId,
        groupConfig: JSON.stringify(settingJson.groupConfig.optionGroupSetting)
      })
      // 将更新后的数据写回文件
      fs.writeFile(filePathSetting, updatedData, 'utf8', (error) => {
        if (error) {
          creatLog(error, 'writeFile-filePathSetting-error')
        }
      })
    } catch (error) {
      creatLog(error, 'filePathSetting-try-catch')
    }
  })
}

// 消息发送处理
const msgStation = async (reJson) => {
  const { wx_type, official, wxid3, msgid } = reJson
  // 处理文本消息（wx_type === 1）
  if (wx_type === 1) {
    let msg = reJson.msg

    // 过滤词逻辑
    if (optionGroupSettingRes?.filterWord?.length) {
      const { filterWord, filterWhole } = optionGroupSettingRes
      if (filterWhole && filterWord.some((filter) => msg.includes(filter))) {
        return run() // 如果启用了全段过滤词并且消息包含任何过滤词，则直接返回不处理
      } else {
        filterWord.forEach((filter) => {
          const escapedFilter = filter.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
          const regex = new RegExp(escapedFilter, 'g')
          msg = msg.replace(regex, '')
        })
      }
    }

    // 替换关键词逻辑
    if (optionGroupSettingRes?.replaceWord?.length) {
      optionGroupSettingRes.replaceWord.forEach((item) => {
        const { keyword, words } = item
        const escapedKeyword = keyword.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
        const regex = new RegExp(escapedKeyword, 'g')
        const randomIndex = Math.floor(Math.random() * words.length)
        const newWord = words[randomIndex]
        msg = msg.replace(regex, newWord)
      })
    }

    // 如果消息不为空，则发送处理后的消息
    if (!!msg) {
      try {
        const postData = { openId: userInfo?.openId, content: msg }
        const response = await axios.post('http://saas-pc-gateway.corpvip.top:8789/turn', postData)
        const result = response?.data?.data?.list?.content
        const successCount = response?.data?.data?.list?.successCount ?? 0

        if (result) {
          // 发送处理后的消息内容
          WxLoader.SendWeChatData(
            processId,
            JSON.stringify({ type: 11036, data: { to_wxid: wxid3, content: result } })
          )
          creatLog({
            desc: `发送${official ? '官方' : '协议'}文字消息`,
            source: msg,
            turn: result,
            msgid,
            wxid: wxid3
          })
        }

        // 记录统计信息
        creatStatic({ msgNum: 1, goodsNum: successCount })
        setTimeout(run, optionGroupSettingRes.interval * 1000)
      } catch (error) {
        creatLog(error, 'axios-turn-catch')
        run()
      }
    }

    // 处理非文本消息（wx_type !== 1）
  } else {
    const { msg, recvWxid, wxid1 } = reJson
    let filePath = null
    let targetData = {}

    switch (wx_type) {
      case 3: // 图片
        if (optionGroupSettingRes?.filterPic) return run()
        targetData = {
          str1: 'IMAGE',
          str2: 'jpg',
          str3: 'img',
          str4: 'cdnmidimgurl',
          num1: 3,
          num2: 11040,
          num3: 2,
          desc: '图片',
          interval: optionGroupSettingRes.interval * 1000 + 1200
        }
        break
      case 43: // 视频
        targetData = {
          str1: 'VOICE',
          str2: 'mp4',
          str3: 'videomsg',
          str4: 'cdnvideourl',
          num1: 43,
          num2: 11042,
          num3: 4,
          desc: '视频',
          interval: optionGroupSettingRes.interval * 1000 + 2500
        }
        break
      case 47: // 表情/GIF
        if (optionGroupSettingRes?.filterEmoji) return run()
        targetData = {
          str1: 'GIF',
          str2: 'gif',
          str3: 'emoji',
          str4: 'cdnurl',
          num1: 47,
          num2: 11043,
          num3: 5,
          desc: '表情',
          interval: optionGroupSettingRes.interval * 1000 + 1200
        }
        break
      default:
        return run() // 不支持的消息类型
    }

    if (!official) {
      parser.parseString(reJson.raw_msg, async (err, result) => {
        mainWindow?.webContents.send('print', result.msg[targetData.str3].$)
        const aes_key = result.msg[targetData.str3].$.aeskey
        const file_id = result.msg[targetData.str3].$[targetData.str4]
        const file_type = targetData.num3
        const date = getT().split(',')[0]
        const savePath = path.join(
          process.cwd(),
          'localcache',
          date,
          recvWxid,
          targetData.str1,
          wxid1
        )

        if (!fs.existsSync(savePath)) {
          fs.mkdirSync(savePath, { recursive: true })
        }

        const fileName = `${msgid}.${targetData.str2}`
        const fileFullPath = path.join(savePath, fileName)

        if (targetData.num1 === 47) {
          const fileData = await downloadGif(file_id)
          filePath = saveFile(recvWxid, wxid1, 'GIF', msgid, 'gif', fileData)
          if (filePath) {
            WxLoader.SendWeChatData(
              processId,
              JSON.stringify({ type: targetData.num2, data: { to_wxid: wxid3, file: filePath } })
            )
            creatLog({ desc: `发送${official ? '官方' : ''}非文字消息`, msgid, msg, wxid: wxid3 })
          }
          setTimeout(run, targetData.interval)
        } else {
          downloadPromise = { reJson, targetData }
          WxLoader.SendWeChatData(
            processId,
            JSON.stringify({
              type: 11230,
              data: { aes_key, file_type, save_path: fileFullPath, file_id }
            })
          )
        }
      })
    } else {
      filePath = await saveUrl(msg, recvWxid, wxid1, targetData.str1, msgid, targetData.str2)
      if (filePath) {
        WxLoader.SendWeChatData(
          processId,
          JSON.stringify({ type: targetData.num2, data: { to_wxid: wxid3, file: filePath } })
        )
        creatLog({ desc: `发送${official ? '官方' : ''}非文字消息`, msgid, msg, wxid: wxid3 })
      }
      setTimeout(run, targetData.interval)
    }
  }
}

function run() {
  if (queue.length) {
    const firstItem = queue.shift()
    msgStation(firstItem)
  } else {
    setTimeout(run, 1000)
  }
}
run()
